; Nurodoma kaip reikia elgtis su pertraukimais

; Macro, kuris skirtas tiems pertraukimams, kurie neperduoda savo klaidos pranešimo,
; todėl, kad galėtume dirbti toliau su viena funkcija ir nepažeisti steko eiliškumo,
; įrašome netikra klaidos koda - 0 į steką.  
%macro ISR_NOERROR 1
  global isr%1
  isr%1:
    cli                         ; Išjungiame pertraukimų mechanizmą
    push byte 0                 ; Į steką įkeliame netikra klaidos kodą
    push byte %1                ; Į steką įkeliame pertraukimo numerį
    jmp isr_common              ; Pereiname prie globalios funkcijos, kuri atlieką likusį darbą
%endmacro

; Macro, kuris skirtas tiems pertraukimams, kurie patys perduoda klaidos pranešimą.
%macro ISR_ERROR 1
  global isr%1
  isr%1:
    cli                         ; Išjungiame pertraukimų mechanizmą
    push byte %1                ; Į steką įkeliame pertraukimo numerį
    jmp isr_common              ; Pereiname prie globalios funkcijos, kuri atlieką likusį darbą
%endmacro

;Macro, kuris turi du parametrus, 1- IRQ numeris, 2- numeris į kurį pervadinamas
%macro IRQ 2
  global irq%1
  irq%1:
    cli                         ; Išjungiame pertraukimų mechanizmą
    push byte 0                 ; Į steką įkeliame netikra klaidos kodą
    push byte %2                ; Į steką įkeliame pertraukimo numerį
    jmp irq_common              ; Pereiname prie globalios funkcijos, kuri atlieką likusį darbą
%endmacro

%macro IRQ_TIMER 2
  global irq%1
  irq%1:
    cli                         ; Išjungiame pertraukimų mechanizmą
    jmp abc              ; Pereiname prie globalios funkcijos, kuri atlieką likusį darbą
%endmacro

ISR_NOERROR 0  ; Division by zero exception  
ISR_NOERROR 1  ; Debug exception 
ISR_NOERROR 2  ; Non maskable interrupt 
ISR_NOERROR 3  ; Breakpoint exception 
ISR_NOERROR 4  ; 'Into detected overflow' 
ISR_NOERROR 5  ; Out of bounds exception 
ISR_NOERROR 6  ; Invalid opcode exception 
ISR_NOERROR 7  ; No coprocessor exception 
ISR_ERROR   8  ; Double fault (pushes an error code) 
ISR_NOERROR 9  ; Coprocessor segment overrun 
ISR_ERROR   10 ; Bad TSS (pushes an error code) 
ISR_ERROR   11 ; Segment not present (pushes an error code) 
ISR_ERROR   12 ; Stack fault (pushes an error code) 
ISR_ERROR   13 ; General protection fault (pushes an error code) 
ISR_ERROR   14 ; Page fault (pushes an error code) 
ISR_NOERROR 15 ; Unknown interrupt exception 
ISR_NOERROR 16 ; Coprocessor fault 
ISR_NOERROR 17 ; Alignment check exception 
ISR_NOERROR 18 ; Machine check exception                         
ISR_NOERROR 19 ; Like yra rezervuoti iki 31 imtinai
ISR_NOERROR 20
ISR_NOERROR 21
ISR_NOERROR 22
ISR_NOERROR 23
ISR_NOERROR 24
ISR_NOERROR 25
ISR_NOERROR 26
ISR_NOERROR 27
ISR_NOERROR 28
ISR_NOERROR 29
ISR_NOERROR 30
ISR_NOERROR 31
IRQ_TIMER   0,    32 ; Timeris
IRQ   1,    33 ; Kliaviatura
IRQ   2,    34
IRQ   3,    35
IRQ   4,    36
IRQ   5,    37
IRQ   6,    38
IRQ   7,    39
IRQ   8,    40
IRQ   9,    41
IRQ  10,    42
IRQ  11,    43
IRQ  12,    44
IRQ  13,    45
IRQ  14,    46
IRQ  15,    47
 
; isr.c
[EXTERN isr_handler]
[EXTERN irq_handler]
[EXTERN task_switch]

; Išsaugome procesoriaus buklę, kernel segmentus nustato,
; iškviečia C funkcija, ir galiausia viska atstato
isr_common:
  pusha                    ; Perkelia į steką edi,esi,ebp,esp,ebx,edx,ecx,eax

  mov ax, ds               ; Išsaugome Duomenų segmento reikšmę žemesniuose 16 bitų registro eax
  push eax                 ; Perkeliame į steką išsaugotą reikšmę

  mov ax, 0x10             ; Užkrauname visu duomenų segmentų selectorius.
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax

  call isr_handler         ; Kviečiame pertraukimo tvarkyklę

  pop eax                  ; Išraukiame iš steko duomenų segmento reikšmę
  mov ds, ax               ; Ir ją užkrauname
  mov es, ax
  mov fs, ax
  mov gs, ax

  popa                     ; Ištraukia iš steko edi,esi,ebp,esp,ebx,edx,ecx,eax
  add esp, 8               ; Ištrina klaidos pranešimą ir pertraukimo numerį
  sti                      ; Įjungia pertraukimų mechanizmą
  iret                     ; Ištraukia iš steko 5 dalykus iškart: CS, EIP, EFLAGS, SS, and ESP

; Išsaugome procesoriaus buklę, kernel segmentus nustato,
; iškviečia C funkcija, ir galiausia viska atstato
irq_common:

  pusha                    ; Perkelia į steką edi,esi,ebp,esp,ebx,edx,ecx,ea

  mov ax, ds               ; Išsaugome Duomenų segmento reikšmę žemesniuose 16 bitų registro eax
  push eax                 ; Perkeliame į steką išsaugotą reikšmę

  mov ax, 0x10             ; Užkrauname visu duomenų segmentų selectorius.
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax

  call irq_handler

  pop eax                  ; Išraukiame iš steko duomenų segmento reikšmę
  mov ds, ax               ; Ir ją užkrauname
  mov es, ax
  mov fs, ax
  mov gs, ax

  popa                     ; Ištraukia iš steko edi,esi,ebp,esp,ebx,edx,ecx,eax
  add esp, 8               ; Ištrina klaidos pranešimą ir pertraukimo numerį
  sti                      ; Įjungia pertraukimų mechanizmą
  iret                     ; Ištraukia iš steko 5 dalykus iškart: CS, EIP, EFLAGS, SS, and ESP

abc:

 ;Notice there is no IRQ number or error code - we don't need them

 pusha          ;Push all standard registers
 push ds        ;Push segment d
 push es        ;Push segmetn e
 push fs        ; ''
 push gs        ; ''
 
 mov eax, 0x10  ;Get kernel data segment
 mov ds, eax    ;Put it in the data segment registers
 mov es, eax
 mov fs, eax
 mov gs, eax

 push esp       ;Push pointer to all the stuff we just pushed

 call task_switch ;Call C code

 mov esp, eax   ;Replace the stack with what the C code gave us

 mov al, 0x20   ;Port number AND command number to Acknowledge IRQ
 out 0x20, al     ;Acknowledge IRQ, so we keep getting interrupts

 pop gs         ;Put the data segments back
 pop fs
 pop es
 pop ds

 popa           ;Put the standard registers back

 ;We didn't push an error code or IRQ number, so we don't have to edit esp now

 iret           ;Interrupt-Return
 